package com.nl.lib_project.net

import android.app.Application
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.ConnectivityManager
import com.google.gson.JsonSyntaxException
import com.hjq.gson.factory.GsonFactory
import com.hjq.http.EasyLog
import com.hjq.http.config.IRequestHandler
import com.hjq.http.exception.*
import com.hjq.http.request.HttpRequest
import com.nl.lib_project.R
import com.nl.lib_project.moshi.HashMapJsonAdapter
import com.nl.lib_project.moshi.LinkHashMapJsonAdapter
import com.nl.lib_project.moshi.LinkListJsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.tencent.mmkv.MMKV
import java.io.IOException
import java.io.InputStream
import java.io.InterruptedIOException
import java.lang.reflect.GenericArrayType
import java.lang.reflect.Type
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import okhttp3.Headers
import okhttp3.Response
import okhttp3.ResponseBody
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject

/** github : https://github.com/getActivity/EasyHttp time : 2019/05/19 desc : 请求处理类 */
class RequestHandler(application: Application) : IRequestHandler {

  private val mMmkv: MMKV = MMKV.mmkvWithID("http_cache_id")
  private var mApplication: Application? = application
  private var mMoshi: Moshi? = null

  init {
    mMoshi =
        Moshi.Builder()
            .add(KotlinJsonAdapterFactory())
            .add(LinkListJsonAdapter.FACTORY)
            .add(HashMapJsonAdapter.FACTORY)
            .add(LinkHashMapJsonAdapter.FACTORY)
            .build()
  }

  @Throws(Exception::class)
  override fun requestSucceed(httpRequest: HttpRequest<*>?, response: Response, type: Type): Any? {
    if (Response::class.java == type) {
      return response
    }
    if (!response.isSuccessful) {
      // 返回响应异常
      throw ResponseException(
          mApplication?.getString(R.string.http_response_error) +
              ", responseCode: " +
              response.code() +
              ", message: " +
              response.message(),
          response)
    }
    if (Headers::class.java == type) {
      return response.headers()
    }
    val body = response.body() ?: return null
    if (ResponseBody::class.java == type) {
      return body
    }

    // 如果是用数组接收，判断一下是不是用 byte[] 类型进行接收的
    if (type is GenericArrayType) {
      val genericComponentType = type.genericComponentType
      if (Byte::class.javaPrimitiveType == genericComponentType) {
        return body.bytes()
      }
    }
    if (InputStream::class.java == type) {
      return body.byteStream()
    }
    if (Bitmap::class.java == type) {
      return BitmapFactory.decodeStream(body.byteStream())
    }
    val text: String =
        try {
          body.string()
        } catch (e: IOException) {
          // 返回结果读取异常
          throw DataException(mApplication?.getString(R.string.http_data_explain_error), e)
        }

    // 打印这个 Json 或者文本
    EasyLog.printJson(httpRequest, text)
    if (String::class.java == type) {
      return text
    }

    // 安卓自带的 JSONObject 的 Gson 是不支持解析的
    if (JSONObject::class.java == type) {
      return try {
        // 如果这是一个 JSONObject 对象
        JSONObject(text)
      } catch (e: JSONException) {
        throw DataException(mApplication?.getString(R.string.http_data_explain_error), e)
      }
    }

    // 安卓自带的 JSONArray 的 Gson 是不支持解析的
    if (JSONArray::class.java == type) {
      return try {
        // 如果这是一个 JSONArray 对象
        JSONArray(text)
      } catch (e: JSONException) {
        throw DataException(mApplication?.getString(R.string.http_data_explain_error), e)
      }
    }
    val result =
        try {
          mMoshi?.adapter<Any>(type)?.fromJson(text)
        } catch (e: JsonSyntaxException) {
          // 返回结果读取异常
          throw DataException(mApplication?.getString(R.string.http_data_explain_error), e)
        }

    if (result is ResponseBaseBean<*>) {
      if (result.code == 200) {
        // 代表执行成功
        return result
      }
      if (result.code == 1001) {
        // 代表登录失效，需要重新登录
        throw TokenException(mApplication?.getString(R.string.http_token_error))
      }
      throw ResultException(result.message, result)
    }
    return result
  }

  override fun requestFail(httpRequest: HttpRequest<*>?, e: Exception): Exception {
    // 判断这个异常是不是自己抛的
    if (e is HttpException) {
      if (e is TokenException) {
        // 登录信息失效，跳转到登录页
      }
      return e
    }
    if (e is SocketTimeoutException) {
      return TimeoutException(mApplication?.getString(R.string.http_server_out_time), e)
    }
    if (e is UnknownHostException) {
      val info =
          (mApplication?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager)
              .activeNetworkInfo
      // 判断网络是否连接
      return if (info != null && info.isConnected) {
        // 有连接就是服务器的问题
        ServerException(mApplication?.getString(R.string.http_server_error), e)
      } else NetworkException(mApplication?.getString(R.string.http_network_error), e)
      // 没有连接就是网络异常
    }

    return if (e is IOException) {
      if (e is InterruptedIOException) {
        // 求情超时的异常捕获
        return TimeoutException(mApplication?.getString(R.string.http_server_out_time), e)
      }
      CancelException(mApplication?.getString(R.string.http_request_cancel), e)
    } else HttpException(e.message, e)
  }

  override fun readCache(httpRequest: HttpRequest<*>, type: Type, cacheTime: Long): Any? {
    val cacheKey = GsonFactory.getSingletonGson().toJson(httpRequest.requestApi)
    val cacheValue = mMmkv.getString(cacheKey, null)
    if (cacheValue == null || "" == cacheValue || "{}" == cacheValue) {
      return null
    }
    EasyLog.printLog(httpRequest, "---------- cacheKey ----------")
    EasyLog.printJson(httpRequest, cacheKey)
    EasyLog.printLog(httpRequest, "---------- cacheValue ----------")
    EasyLog.printJson(httpRequest, cacheValue)
    return GsonFactory.getSingletonGson().fromJson(cacheValue, type)
  }

  override fun writeCache(httpRequest: HttpRequest<*>, response: Response, result: Any): Boolean {
    val cacheKey = GsonFactory.getSingletonGson().toJson(httpRequest.requestApi)
    val cacheValue = GsonFactory.getSingletonGson().toJson(result)
    if (cacheValue == null || "" == cacheValue || "{}" == cacheValue) {
      return false
    }
    EasyLog.printLog(httpRequest, "---------- cacheKey ----------")
    EasyLog.printJson(httpRequest, cacheKey)
    EasyLog.printLog(httpRequest, "---------- cacheValue ----------")
    EasyLog.printJson(httpRequest, cacheValue)
    return mMmkv.putString(cacheKey, cacheValue).commit()
  }
}
